#include "stdafx.h"
#include "GLHandler.h"
#include "Utility.h"
using namespace Utility;

//global variable
GLfloat zoomDelta=0.0;//zoom delta
GLuint	axiesIndex, demoCubeIndex, objModelIndex;
GLfloat light_ambient[]={0.5,0.5,0.5,1.0};
GLfloat light_diffuse[]={0.7,0.7,0.7,1.0};
GLfloat light_specular[]={1.0,1.0,1.0,1.0};
GLfloat light_position[]={0.0,3.0,8.0,0.0};

GLfloat mat_ambient[]={0.4, 0.0, 0.0, 1.0};
GLfloat mat_diffuse[]={0.8, 0.8, 0.8, 1.0};
GLfloat mat_specular[]={1.0, 1.0, 1.0, 1.0};
GLfloat mat_shininess[]={100.0 };

float			GLHandler::rotateAngle = 0.0;
float			GLHandler::xRotate = 0.0;
float			GLHandler::yRotate = 0.0;
float			GLHandler::zRotate = 0.0;
GLMmodel*		GLHandler::pObjModel = NULL;
bool			GLHandler::isShowCusModel = false;
ZWFontWGLBase	GLHandler::eularInfoFont;
ZWFontWGLBase	GLHandler::frameRateInfoFont;
ComPortHandler* GLHandler::pComPortHandler = NULL;
TimeCounter		GLHandler::frameTimer;
bool			GLHandler::frameFlag = false;

GLHandler::GLHandler()
{
}

GLHandler::~GLHandler()
{
	if (pObjModel)
	{
		glmDelete(pObjModel);
		pObjModel = NULL;
	}
}

void GLHandler::initLight()
{
	glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
	glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
	glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);

	glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
	glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
	glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
	glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);

	glEnable(GL_LIGHT0);
}

//off the light
void  GLHandler::initDrawList()
{
	axiesIndex=glGenLists(1);
	if(axiesIndex>0)
	{
		glNewList(axiesIndex,GL_COMPILE);
			glPushAttrib(GL_CURRENT_BIT);
			glDisable(GL_LIGHTING);
			glLineWidth(1.0);
			glBegin(GL_LINES);
				glColor3f(0.0,0.0,1.0);
				glVertex3f(-100,0,0);
				glVertex3f(100,0,0);
				glColor3f(0.0,1.0,0.0);
				glVertex3f(0,-100,0);
				glVertex3f(0,100,0);
				glColor3f(1.0,0.0,0.0);
				glVertex3f(0,0,-100);
				glVertex3f(0,0,100);
			glEnd();
			glEnable(GL_LIGHTING);
			glPopAttrib();
		glEndList();
	}
	demoCubeIndex=glGenLists(1);
	if (demoCubeIndex>0)
	{
		glNewList(demoCubeIndex, GL_COMPILE);
		glDisable(GL_LIGHTING);
		glPushAttrib(GL_CURRENT_BIT);
			glBegin(GL_POLYGON);
				glNormal3f(0.0,0.0,1.0);
				glColor3f(1.0,0.0,0.0);
				glVertex3f(-2.0,1.0,1.0);
				glVertex3f(-2.0,-1.0,1.0);
				glVertex3f(2.0,-1.0,1.0);
				glVertex3f(2.0,1.0,1.0);
			glEnd();
			glBegin(GL_POLYGON);
				glNormal3f(0.0,-1.0,0.0);
				glColor3f(0.0,1.0,0.0);
				glVertex3f(-2.0,-1.0,1.0);
				glVertex3f(-2.0,-1.0,-1.0);
				glVertex3f(2.0,-1.0,-1.0);
				glVertex3f(2.0,-1.0,1.0);
			glEnd();
			glBegin(GL_POLYGON);
				glNormal3f(0.0,0.0,-1.0);
				glColor3f(0.0,0.0,1.0);
				glVertex3f(2.0,1.0,-1.0);
				glVertex3f(-2.0,1.0,-1.0);
				glVertex3f(-2.0,-1.0,-1.0);
				glVertex3f(2.0,-1.0,-1.0);
			glEnd();
			glBegin(GL_POLYGON);
				glNormal3f(0.0,1.0,0.0);
				glColor3f(1.0,1.0,0.0);
				glVertex3f(-2.0,1.0,-1.0);
				glVertex3f(-2.0,1.0,1.0);
				glVertex3f(2.0,1.0,1.0);
				glVertex3f(2.0,1.0,-1.0);
			glEnd();
			glBegin(GL_POLYGON);
				glNormal3f(-1.0,0.0,0.0);
				glColor3f(1.0,0.0,1.0);
				glVertex3f(-2.0,1.0,-1.0);
				glVertex3f(-2.0,-1.0,-1.0);
				glVertex3f(-2.0,-1.0,1.0);
				glVertex3f(-2.0,1.0,1.0);
			glEnd();
			glBegin(GL_POLYGON);
				glNormal3f(1.0,0.0,0.0);
				glColor3f(0.0,1.0,1.0);
				glVertex3f(2.0,1.0,1.0);
				glVertex3f(2.0,-1.0,1.0);
				glVertex3f(2.0,-1.0,-1.0);
				glVertex3f(2.0,1.0,-1.0);
			glEnd();
		glPopAttrib();
		glEnable(GL_LIGHTING);
		glEndList();
	}
}

void  GLHandler::putFrameRateInfoText()
{
	if (!frameFlag)
	{
		frameTimer.Start();
	}
	else
	{
		frameTimer.End();
		float frameRate = 1.0/frameTimer.getElapseTime();
		CString cstr = CString(L"fps: ") + Helper::convertToCString(frameRate);
		frameRateInfoFont.PrintText(10, 10, const_cast<TCHAR*> (cstr.GetString()));
		frameTimer.Reset();
		frameTimer.Start();
	}
	frameFlag = true;
}

void  GLHandler::renderScene()
{
	glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
	glLoadIdentity();
	gluLookAt(0,0,5,0,0,-1,0,1,0);
	glLightfv(GL_LIGHT0, GL_POSITION, light_position);
	glPushMatrix();
		glTranslatef(0,0,zoomDelta);
		glCallList(axiesIndex); 
		glRotatef(rotateAngle, -xRotate, zRotate, yRotate);
		if (isShowCusModel)
		{
			glEnable(GL_LIGHTING);
				glCallList(objModelIndex);
			glDisable(GL_LIGHTING);
		}
		else
		{
			glCallList(demoCubeIndex); 
		}
		putEularInfoText();
		putFrameRateInfoText();
	glPopMatrix();
}

void GLHandler::setViewPort(GLsizei w, GLsizei h)
{
	if(!h)
		return ;
	glViewport(0,0,(GLsizei)w,(GLsizei)h);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(60.0f,(GLdouble)w/h,1.0f,50.0f); 
	glMatrixMode(GL_MODELVIEW);	
}

bool GLHandler::initGL()
{
	GLenum err = glewInit();  
	if (err != GLEW_OK )  
	{  
		return false;
	}
	glClearColor(0.0,0.0,0.0,0.0);
	glShadeModel(GL_SMOOTH);
	glHint(GL_LINE_SMOOTH_HINT|GL_POINT_SMOOTH_HINT,GL_NICEST);
	glEnable(GL_LINE_SMOOTH);
	glEnable(GL_DEPTH_TEST);
	//initialize light
	initLight();
	//initialize draw list
	initDrawList();
	//init Font
	initFont();
	return true;
}

void GLHandler::setRotateParam( float rAngle, float xR, float yR, float zR )
{
	rotateAngle = rAngle;
	xRotate = xR;
	yRotate = yR;
	zRotate = zR;
}

void GLHandler::getRotateFromComHandler()
{
	if (pComPortHandler->isReadingComPort())
	{
		pComPortHandler->getRotateValueByQuat(rotateAngle, xRotate, yRotate, zRotate);
	}
}

bool GLHandler::generateGLMCallList( char* objFile, const GLfloat scale)
{
	if (pObjModel!=NULL)
	{
		glmDelete(pObjModel);
	}

	pObjModel = glmReadOBJ(objFile);
	if (!pObjModel) 
	{
		return false;
	}
	glmUnitize(pObjModel);
	glmScale(pObjModel,scale);
	glmFacetNormals(pObjModel);
	glmVertexNormals(pObjModel, 90.0);

	objModelIndex= glGenLists(1);
	glNewList(objModelIndex, GL_COMPILE);
		glmList(pObjModel, GLM_SMOOTH | GLM_MATERIAL); 
	glEndList();

	isShowCusModel = true;
	return true;
}

void GLHandler::putEularInfoText()
{
	float roll = pComPortHandler->getRoll();
	float pitch = pComPortHandler->getPitch();
	float yaw = pComPortHandler->getYaw();
	CString eularInfo = CString(L"Roll: ") + Helper::convertToCString(roll);
	eularInfoFont.PrintText(10, 70, const_cast<TCHAR*>(eularInfo.GetString()) );
	eularInfo = CString(L"Pitch: ")+ Helper::convertToCString(pitch);
	eularInfoFont.PrintText(10, 50, const_cast<TCHAR*>(eularInfo.GetString()) );
	eularInfo =  CString(L"Yaw: ")+ Helper::convertToCString(yaw);
	eularInfoFont.PrintText(10, 30, const_cast<TCHAR*>(eularInfo.GetString()) );

}

void GLHandler::initFont()
{
	eularInfoFont.SetFontColor(255, 255, 255);
	eularInfoFont.BuildFont(20, 10, L"Calibri");
	frameRateInfoFont.SetFontColor(255, 255, 255);
	frameRateInfoFont.BuildFont(20, 10, L"Calibri");
}

void GLHandler::setComPortHandler( ComPortHandler* cpHander )
{
	pComPortHandler = cpHander;
}
